// ml278
// Copyright (C) 2008 Bjørn Øivind Bjørnsen, Aleksander Gjermundsen, Knut Andre Tidemann, Thomas Hansen
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#ifndef __PLANETARYZONE_H_
#define __PLANETARYZONE_H_

#include "planetaryzonerenderable.h"
#include <vector>
#include <OgreSceneNode.h>
#include "planetarycommon.h"

namespace Ogre
{
	class PlanetaryLODJoint;
	class PlanetarySceneManager;
	class PlanetaryOptions;
	class PlanetaryPlanet;
	class PlanetaryPage;

	/**
	 * Implementation of a Zone on the planet.
	 * Each planet is subdivided into six zones -  front, back, left, right, top, bottom - each of them
	 * corresponding to a side on a cube. This is the highest level of the hierarchy of classes that control
	 * what the planet actually looks like.
	*/
	class PlanetaryZone
	{
	public:
		PlanetaryZone(PlanetarySceneManager *mgr);
		~PlanetaryZone();

		void init(unsigned int zone,PlanetaryPlanet *parent);
		void load();
		void unload();
		void uninit();

		inline SceneNode *getSceneNode()
		{
			return mSceneNode;
		}

		void updatePaging(Camera *cam);

		/// Set the material to be used by this zone and it's sub entities
		void setMaterial(MaterialPtr mat);

		inline PlanetaryPlanet *getParent()
		{
			return mParent;
		}

		inline MaterialPtr getMaterial()
		{
			return mRenderable->getMaterial();
		}

		inline bool isRenderableVisible()
		{
			return mRenderable->isVisible();
		}
		
		inline unsigned int getZone()
		{
			return mZone;
		}
		
		inline PlanetaryZone *getNeighbour(NEIGHBOUR n)
		{
			return mNeighbours[n];
		}

		void setNeighbour(NEIGHBOUR n, PlanetaryZone *p);

	private:
		/// Notify a neighbour, n implies the relationship this neighour has to the one getting notified: n = NORTH means that the neighour getting notified is north of the calling neighour
		void _notifyNeighbour(NEIGHBOUR n,PlanetaryZone *callingNeighour);

		/// Used by the zone to notify it self that it has changed render LOD and might need to add / remove joints
		void _notifySelf();

		PlanetarySceneManager 	*mSceneMgr;
		PlanetaryOptions	*mOptions;
		PlanetaryPlanet		*mParent;

		/// Renderable for this zone
		PlanetaryZoneRenderable *mRenderable;

		/// Scene node for this zone
		SceneNode *mSceneNode;

		/// Neighbours of this zone
		PlanetaryZone *mNeighbours[4];

		/// LOD joints
		PlanetaryLODJoint *mLODJoints[4];

		/// This zone index
		unsigned int mZone;

		/// Pages of this zone
		std::vector< std::vector<PlanetaryPage *> > mPages;

		/// true if the zone has been initialised
		bool mIsInit;
		/// true if the zone has been loaded
		bool mIsLoaded;
	};
}

#endif
